extends Node2D


export(Color) var background_color
export(Color) var floor_color

var MAX_DOTS = 100
var GROUP_BALL :String = 'group_dots'
#var AUDIO_PATH = "res://Audio/sounds/"
var AUDIO_PATH = "res://Audio/6415/"
#var AUDIO_PATH = "res://Audio/piano_keys/"
var RADIUS_MIN = 10
var RADIUS_FACTOR = 30


var window_rect :Rect2
var screen_center :Vector2 = Vector2.ZERO
var pm :PhysicsMaterial = null
var ground :StaticBody2D = null
onready var dots_room = $Dots

var balls = {}
var streamlist = []

# audio record
var effect
var recording

onready var record_btn = $Control/MarginContainer/VBoxContainer/HBoxContainer/Record
onready var save_btn = $Control/MarginContainer/VBoxContainer/HBoxContainer/Save
onready var play_btn = $Control/MarginContainer/VBoxContainer/HBoxContainer/Play
onready var status = $Control/MarginContainer/VBoxContainer/HBoxContainer/Status
onready var pause_btn = $Control/MarginContainer/VBoxContainer/VBoxContainer/Button

var btn_text = {
	'Record': "录制", 'Save': '保存', 'Play':'试听', 'Stop':'停止',
	'Saving':'保存中。。。', 'Pausing':'暂停中。。。', 'Resume':'继续',
	'Playing':'试听中...' , 'Recording':'录制中...'
}
# Called when the node enters the scene tree for the first time.
func _ready():
	randomize()
	window_rect = get_viewport_rect()
#	screen_center = Vector2(window_rect.size.x, window_rect.size.y) / 2
	VisualServer.set_default_clear_color(background_color)
	pm = PhysicsMaterial.new()
	pm.bounce = 1	
	create_ground()
	load_sounds(AUDIO_PATH)
	
	record_btn.text = btn_text['Record']
	save_btn.text = btn_text['Save']
	save_btn.disabled = true
	play_btn.text = btn_text['Play']
	play_btn.disabled = true
	pause_btn.text = btn_text['Pausing']
	pause_btn.disabled = true
	record_btn.connect("pressed", self, "on_Record_button_pressed")
	save_btn.connect("pressed", self, "on_Save_button_pressed")
	play_btn.connect("pressed", self, "on_Play_button_pressed")
	pause_btn.connect("pressed", self, "resume")
	
	var idx = AudioServer.get_bus_index('Master')
	effect = AudioServer.get_bus_effect(idx, 0)
	$AudioStreamPlayer.connect("finished", self, "on_AudioStreamPlayer_finished")
	
	
func on_Record_button_pressed():
	if balls.size() == 0:
		return
	if effect.is_recording_active():
		recording = effect.get_recording()
		play_btn.disabled = false
		save_btn.disabled = false
		effect.set_recording_active(false)
		record_btn.text = btn_text['Record']
		status.text = ""
	else:
		play_btn.disabled = true
		save_btn.disabled = true
		effect.set_recording_active(true)
		record_btn.text = btn_text['Stop']
		status.text = btn_text['Recording']
		
		
func on_Save_button_pressed():
	print("Saving")
	var save_path = "user://%s.wav" % [OS.get_system_time_secs()]
	recording.stereo = true
	recording.save_to_wav(save_path)
	var os_file_path = ProjectSettings.globalize_path(save_path)
	status.text = "保存文件到: %s\n(%s)" % [save_path, os_file_path]
	var shell_open_path = ProjectSettings.globalize_path('user://')
	print("shell_open_path = ", shell_open_path)
	print(OS.shell_open(shell_open_path))
	
	
func pause_all():
	get_tree().paused = true
	pause_btn.text = btn_text['Pausing']
	pause_btn.disabled = true
	pause_btn.visible = true

func resume():
	get_tree().paused = false
	pause_btn.visible = false
	
func on_Play_button_pressed():
	pause_all()
	if not recording:
		return
	print("Playing")
	play_btn.disabled = true
	print(recording)
	print(recording.format)
	print(recording.mix_rate)
	print(recording.stereo)
	var data = recording.get_data()
#	var data = recording.data
	print(data.size())
	$AudioStreamPlayer.stream = recording
	$AudioStreamPlayer.play()
	status.text = btn_text['Playing']

	
func on_AudioStreamPlayer_finished():
	status.text = ""
	play_btn.disabled = false
	pause_btn.text = btn_text['Resume']
	pause_btn.disabled = false

class Ball:
	var index = -1
	var center = Vector2.ZERO
	var radius = 1.0
	var color :Color = Color.white
	var playing = false


func _draw():
	draw_ground()
	for rigid in get_tree().get_nodes_in_group(GROUP_BALL):
		var ball = balls[rigid.get_instance_id()]
		draw_circle(rigid.position, ball.radius, ball.color)
	
	
func draw_ground():
	draw_rect(Rect2(ground.position, Vector2(window_rect.size.x, 5 * 2)), floor_color)
	
func create_ball(center, radius, color):
	var ball = Ball.new()
	ball.center = center
	ball.radius = radius
	ball.color = color
		
func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and event.is_pressed():
			var mousePos = get_global_mouse_position()
			if mousePos.y < 50: # button hbox height
				return
			var color = Color(randf(), randf(), randf())
			var rad = max(window_rect.size.y / RADIUS_FACTOR * randf(), randi() % RADIUS_MIN + RADIUS_MIN )
			create_rigid(mousePos, rad, color)
#			print(balls)


func create_rigid(pos, rad, color):
	if balls.size() >= MAX_DOTS:
		return
	var ball = Ball.new()
	ball.center = pos
	ball.radius = rad
	ball.color = color
	var rigid = RigidBody2D.new()
	var cirshape = CircleShape2D.new()
	cirshape.radius = rad
	var collison = CollisionShape2D.new()
	collison.shape = cirshape
	rigid.add_child(collison)
	rigid.position = pos
	rigid.physics_material_override = pm

	var ve = VisibilityNotifier2D.new()
	ve.rect = Rect2(Vector2(rad, rad) * -1, Vector2(rad, rad) * 2)
	rigid.add_child(ve)
	ve.connect("screen_exited", self, "on_rigid_screen_exited", [rigid])
	dots_room.add_child(rigid)
	rigid.add_to_group(GROUP_BALL)
	balls[rigid.get_instance_id()] = ball
	
	rigid.contact_monitor = true
	rigid.contacts_reported = 1
	rigid.connect("body_entered", self, "_on_RigidBody2D_body_entered", [rad])
	return rigid


func remove_rigid(rigid):	
#	print("queue free ", rigid)
	rigid.remove_from_group(GROUP_BALL)
	balls[rigid.get_instance_id()] = null
	balls.erase(rigid.get_instance_id())
	rigid.queue_free()

func on_rigid_screen_exited(something):
#	print(something, "exit screen")
	call_deferred("remove_rigid", something)

func create_ground():
	ground = StaticBody2D.new()
	var ground_shape = RectangleShape2D.new()
	var collision = CollisionShape2D.new()
	ground_shape.extents = Vector2(window_rect.size.x, 5)
	collision.shape = ground_shape
	ground.add_child(collision)
	ground.position.y = window_rect.size.y - ground_shape.extents.y * 2
	ground.physics_material_override = pm
	add_child(ground)
	

	
func _process(_delta):		
	update()


func _on_RigidBody2D_body_entered(body, radius):
	if body is RigidBody2D:
		var ball = balls[body.get_instance_id()]
		if ball.radius > radius and not ball.playing: #只选大点的球播放
			play_sound(ball, body)
			ball.playing = true
#		else:
#			print("ball %s is playing ,skipped" % [ball.to_string()])
		

func play_sound(ball :Ball, body :RigidBody2D):
	var audioPlayer = AudioStreamPlayer2D.new()
	var audio_file = streamlist[randi() % streamlist.size()]
#	print(audio_file)
	audioPlayer.stream = load(audio_file)
	body.add_child(audioPlayer)
	audioPlayer.play()
	audioPlayer.connect("finished", self, "on_play_sound_finished", [audioPlayer, ball])


func on_play_sound_finished(ap, ball):
	call_deferred("remove_audio_player", ap, ball)


func remove_audio_player(ap, ball):
	ap.queue_free()
	ball.playing = false
#	print(ap ," removed")

func load_sounds(path :String):
	var dir = Directory.new()
	if dir.open(path) == OK:
		dir.list_dir_begin()
		var filename = dir.get_next()
		while filename != '':
			if filename.ends_with('.ogg'):
				streamlist.append(path + filename)			
			filename = dir.get_next()


